package cn.lzx.hrm.service.impl;

import cn.lzx.exctption.GlobalException;
import cn.lzx.hrm.domain.CourseType;
import cn.lzx.hrm.mapper.CourseTypeMapper;
import cn.lzx.hrm.service.ICourseTypeService;
import cn.lzx.hrm.vo.CrumbsVo;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.io.Serializable;
import java.util.*;

/**
 * <p>
 * 课程目录 服务实现类
 * </p>
 *
 * @author lzx
 * @since 2022-01-06
 */
@Service
public class CourseTypeServiceImpl extends ServiceImpl<CourseTypeMapper, CourseType> implements ICourseTypeService {


    @Autowired
    private RedisTemplate redisTemplate;
    //redis的key
    private static  final  String COURSETYPE_TREEDATA_IN_CACHE = "courseType_treeData_in_cache";
    @Autowired
    private CourseTypeMapper courseTypeMapper;


    @Override
    public List<CourseType> treeData(Long pid) {
        //通过redis的key为courseType_treeData_in_cache获取缓存中的数据
        List<CourseType> courseTypes = (List<CourseType>) redisTemplate.opsForValue().get(COURSETYPE_TREEDATA_IN_CACHE);
        if(courseTypes!=null) {
            return courseTypes;
        }else {
            synchronized (this.getClass()){
                courseTypes = (List<CourseType>) redisTemplate.opsForValue().get(COURSETYPE_TREEDATA_IN_CACHE);
                if (courseTypes==null){
                    //如果缓存中的数据 为null 就调用loadTreeDataByLood 方法 重新获取数据库中的数据
                    List<CourseType> courseTypeList = loadTreeDataByLood(pid);
                    //再将数据库中的数据重新保存到缓存区中 key为COURSETYPE_TREEDATA_IN_CACHE 数据为courseTypeList
                    redisTemplate.opsForValue().set(COURSETYPE_TREEDATA_IN_CACHE,courseTypeList);
                    return courseTypeList;
                }
            return courseTypes;
            }
        }
    }


    /**
     * 方案一  通过循环  只操作一次数据库
     * @param pid
     * @return
     */
    public List<CourseType> loadTreeDataByLood(Long pid) {
        //返回
        ArrayList<CourseType> result = new ArrayList<>();
        //查询全部
        List<CourseType> courseTypes = courseTypeMapper.selectList(null);
        //将courseType的儿子  pid作为key 自己作为儿子保存到map中
        HashMap<Long, CourseType> map = new HashMap<>();
        //建立联系
        courseTypes.forEach(courseType -> {
            map.put(courseType.getId(),courseType);
        });
        //遍历所有的courseTypes
        courseTypes.forEach(courseType -> {
            Long ppid = courseType.getPid();
            //判断是否是一级 如果是
            if(ppid.longValue()==pid.longValue()) {
                result.add(courseType);
            }else {
                //获取父亲
                CourseType parent= map.get(ppid);
                parent.getChildren().add(courseType);
            }
        });
        return result;
    }


    /**
     * 方案二  通过递归的思想 优点 代码少 缺点 操作多次数据库
     * @param pid
     * @return
     */
    /**@Override
    public List<CourseType> treeData(Long pid)
    查询出所有的顶级课表分类 传入的pid为0
    List<CourseType> courseTypes = courseTypeMapper.selectList(new EntityWrapper<CourseType>().eq("pid", pid));
    递归出口 如果courseTypes没值就直接返回
        if (courseTypes==null||courseTypes.size()<1)
            return null;
    遍历
        courseTypes.forEach(courseType -> {
    courseType的pid就是他上一级的id
        Long ppid = courseType.getPid();
    自己调用自己
        List<CourseType> children = treeData(ppid);
    将自己设置到他的父类CourseType字段children中
        courseType.setChildren(children);
    });
        return courseTypes;
}*/

    /**
     * 延迟双删 先操作数据库 再延迟双删
     * @param entity
     * @return
     */
    @Override
    public boolean insert(CourseType entity) {
        super.insert(entity);
        redisTemplate.delete(COURSETYPE_TREEDATA_IN_CACHE);
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        redisTemplate.delete(COURSETYPE_TREEDATA_IN_CACHE);
        return true;
    }

    /**
     * 延迟双删 先操作数据库 再延迟双删
     * @param id
     * @return
     */
    @Override
    public boolean deleteById(Serializable id) {
        super.deleteById(id);
        redisTemplate.delete(COURSETYPE_TREEDATA_IN_CACHE);
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        redisTemplate.delete(COURSETYPE_TREEDATA_IN_CACHE);
        return true;
    }

    /**
     * 延迟双删 先操作数据库 再延迟双删
     * @param entity
     * @return
     */
    @Override
    public boolean updateById(CourseType entity) {
        super.updateById(entity);
        redisTemplate.delete(COURSETYPE_TREEDATA_IN_CACHE);
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        redisTemplate.delete(COURSETYPE_TREEDATA_IN_CACHE);
        return true;
    }

    /**
     * 获取面包屑
     * @param typeId
     * @return
     */
    @Override
    public List<CrumbsVo> queryCrumbs(Long typeId) {
        // 定义返回类型List
        List<CrumbsVo> list = new ArrayList<>();
        //空值校验
        if(typeId==null){
            throw new GlobalException("请选中课程再操作");
        }
        //通过typeid获取type类型
        CourseType courseType = courseTypeMapper.selectById(typeId);
        //通过自己查出自己的path
        String path = courseType.getPath();
        //分割path为数组
        String[] paths = path.split("\\.");
        for (String idstr : paths) {
            CrumbsVo crumbsVo = new CrumbsVo();
            //将string转换为long
            Long id = Long.valueOf(idstr);
            //id,查询课程可以构造自己
            CourseType owner = courseTypeMapper.selectById(id);
            crumbsVo.setOwnerCourseType(owner);
            //通过自己的pid获取所有的儿子 排除自己
            Long pid = owner.getPid();
            List<CourseType> otherCourseTypes = courseTypeMapper.selectList(new EntityWrapper<CourseType>().eq("pid", pid));
            //排除自己
            Iterator<CourseType> iterator = otherCourseTypes.iterator();
            //如果iterator有下一个
            while (iterator.hasNext()){
                //就获取下一个
                CourseType courseType1 = iterator.next();
                //如果这个的id和传进来的id相同 就移除
                if (id.longValue()==courseType1.getId().longValue()){
                    iterator.remove();
                    break;
                }
            }
            crumbsVo.setOtherCourseTypes(otherCourseTypes);
            list.add(crumbsVo);
        }
        return list;
    }
}
